/*
*	(*^。^*) TFrameWork License (*^。^*)
*/

/*
 *  Title :  
 *          
 *  Description :  
 *          
 *          
 *  Date : 
 *
 *  Author : DengPing
 *
 *  Modify : 
 */

using System;
using UnityEngine;

namespace TFrameWork.Module.ActionEditor
{
    public enum UpdateMode
    {
        DSPClock, //这是默认的更新模式。在这种模式下，PlayableDirector 使用 Unity 的 DSP 时钟来更新其 Playable。这意味着 PlayableDirector 将根据 DSP 时钟更新播放状态，与游戏中的 Time.deltaTime 和 Time.timeScale 无关。这对于需要精确的同步和时间控制的应用程序很有用，比如音频和视频播放
        GameTime, //在这种模式下，PlayableDirector 使用游戏时间来更新其 Playable。这意味着 PlayableDirector 将根据 Unity 的游戏时间更新播放状态，与 Time.deltaTime 和 Time.timeScale 相关联。这是在需要与游戏逻辑相同的时间轴播放的情况下使用的常见模式。
        UnscaledGameTime, //与 "Game Time" 模式类似，但是忽略了 Time.timeScale。这意味着即使游戏时间缩放为0，PlayableDirector 仍然会更新其 Playable。这对于在游戏暂停时仍然播放 Timeline 很有用。
        Manual, //更新模式为手动。您需要使用您自己的 deltaTime 手动调用 PlayableGraph.Evaluate。这对于与游戏其他部分完全断开连接的图非常有用。例如，本地化的子弹时间。
    }

    public enum WrapMode
    {
        None,
        Loop,
        Hold,
    }

    public class TimeLineAction : MonoBehaviour
    {
        /// <summary>
        /// 播放文件
        /// </summary>
        public ActionData actionData;

        public UpdateMode updateMode = UpdateMode.GameTime;

        public bool PlayOnAwake = false;

        public WrapMode wrapMode = WrapMode.None;

        /// <summary>
        /// 初次播放时，Playable 应该开始的时间。
        /// </summary>
        public int InitialTime = 0;

        private int currentFrameIndex; // 当前是第几帧
        private float playTotalTime; // 当前播放的总时间
        private int frameRote; // 当前技能的帧率
        private bool isPlaying;
        private Action playend = null;

        private IOnAnimationTrack _animationTrack;
        private IOnAudioTrack _audioTrack;
        private IOnParticleTrack _particleTrack;
        private IOnTriggerTrack _TriggerTrack;
        private IOnSignalTrack _signalTrack;

        private void Awake()
        {
            _animationTrack = new CustomOnAnimationTrack();
            _animationTrack.Init(this);
            _audioTrack = new CustomOnAudioTrack();
            _audioTrack.Init(this);
            _particleTrack = new CustomOnParticleTrack();
            _particleTrack.Init(this);
            _TriggerTrack = new CustomOnTriggerTrack();
            _TriggerTrack.Init(this);
            _signalTrack = new CustomOnSignalTrack();
            _signalTrack.Init(this);

        }


        /// <summary>
        /// 播放技能
        /// </summary>
        /// <param name="actionData">技能配置</param>
        public void PlaySkill(ActionData actionData, Action playend)
        {
            this.actionData = actionData;
            currentFrameIndex = -1;
            playTotalTime = 0;
            frameRote = actionData.FrameRote;
            isPlaying = true;
            this.playend = playend;
            UpdateTick();
        }

        private void Update()
        {
            if (isPlaying && updateMode == UpdateMode.GameTime)
            {
                playTotalTime += Time.deltaTime;
                // 根据总时间判断当前是第几帧
                int targetFrameIndex = (int)(playTotalTime * frameRote);
                // 防止一帧延迟过大，追帧
                while (currentFrameIndex < targetFrameIndex)
                {
                    // 驱动一次技能
                    UpdateTick();
                }

                // 如果到达最后一帧，技能结束
                if (targetFrameIndex >= actionData.FrameCount)
                {
                    isPlaying = false;
                    playend?.Invoke();
                    Clean();
                }
            }
        }

        private void Clean()
        {

        }

        private void UpdateTick()
        {
            currentFrameIndex += 1;
            TickAction<AnimationEvent>(_animationTrack, currentFrameIndex);
            TickAction<AudioEvent>(_audioTrack, currentFrameIndex);
            TickAction<PrefabEvent>(_particleTrack, currentFrameIndex);
            TickAction<TriggerEvent>(_TriggerTrack, currentFrameIndex);
            TickAction<SignalEvent>(_signalTrack, currentFrameIndex);
        }

        /// <summary>
        /// todo 为测试功能 暴力遍历 等待优化
        /// </summary>
        /// <param name="track"></param>
        /// <param name="currentFrame"></param>
        /// <typeparam name="T"></typeparam>
        private void TickAction<T>(IOnTrack track, int currentFrame) where T : TrackEventBase, new()
        {
            TrackData animationData = actionData.GetTrackList<T>();
            for (int i = 0; i < animationData.trackDatas.Count; i++)
            {
                TrackItemData data = animationData.trackDatas[i];
                var currentEvents = data.TryGetTickEvent(currentFrame);
                if (currentEvents != null && currentEvents.Count > 0)
                {
                    if (typeof(T) == typeof(AnimationEvent))
                    {
                        Debug.Log(currentEvents.Count);
                    }

                    for (int j = 0; j < currentEvents.Count; j++)
                    {
                        var eventData = currentEvents[j];
                        track.currentFrame = currentFrame;
                        if (currentFrameIndex == eventData.startIndex)
                        {
                            track.OnStart(eventData);
                        }

                        if (eventData.durationIndex + eventData.startIndex == currentFrameIndex)
                        {
                            track.OnFinish();
                        }

                        if (eventData.durationIndex > 0)
                        {
                            track.OnUpdate(currentFrame);
                        }
                    }
                }
            }
        }


        private void OnDrawGizmos()
        {
            if (_TriggerTrack is CustomOnTriggerTrack trigger)
            {
                trigger.OnDrawGizmos();
            }
        }
    }
}
